package cn.quan.evernote;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;

import android.util.Log;

/**
 * 概要：后台吧Client传来的数据，通过EvernoteAPI上传到Evernote数据库
 * 详细：
 * @author yunfeng.quan@gmail.com
 *
 */
public class PicmoService extends Service {
	//Evernote interface API
	private static SimpleEvernote picmo;//evernote api
	//flags
	// false:结束命令来的时候，直接结束
	// true:结束命令来的时候，等待后续处理以后结束
	private boolean waitExit;
	
	@Override
	public IBinder onBind(Intent arg0) {
		Log.d(TAG,"@onBind");
		return rmiPicmoService;
	}
	@Override
	public void onRebind(Intent intent) {
		Log.d(TAG,"@onRebind");
		super.onRebind(intent);
	}
	@Override
	public boolean onUnbind(Intent intent) {
		Log.d(TAG,"@onUnbind");
		//waitExit = true;//如果接触绑定的话，默认是要结束服务。前提是绑定个数限定为1个
		rmiPicmo = null;
		return super.onUnbind(intent);
	}	
	@Override
	public void onCreate() {
		Log.d(TAG,"@onCreate");
		super.onCreate();
		//setForeground(true);//让服务启动时间更长一点
		//state initialize
		changeState(state_none);
		//flags initialize
		//waitExit = false;
		picmo = null;//初始化
	}
	@Override
	public void onStart(Intent intent, int startId) {
		Log.d(TAG,"@onStart");
		super.onStart(intent, startId);
		//flags initialize
		waitExit = false;
		//Log.d(TAG,"@start state,loginReady,threadQueue <"+state+","+loginReady+","+threadQueue.isAlive()+">");

		//启动主线程
		startQueue();
		//start 
		execute(cmd_start);

	}
	@Override
	public void onDestroy() {
		Log.d(TAG,"@onDestroy");
		super.onDestroy();
	}

	//state machine
	private void execute(int cmd){
		//Log.d(TAG,"@cmd: "+cmd);
		switch(state){
		case state_none:
			switch(cmd){
			case cmd_login:
				changeState(state_login);
				//login
				loginPicmo();
				break;
			case cmd_exit:
				changeState(state_none);
				stopSelf();
				break;
			case cmd_start:
				//do nothing
				break;
			default:
				//do nothing
				break;
			}
			break;
		//
		case state_login:
			switch(cmd){
			case res_login_success:
				changeState(state_login_success);
				resLogin(true,0,"");
				execute(cmd_idle);
				break;
			case res_login_fail:
				changeState(state_login_fail);
				resLogin(false,picmo.getErrCode(),picmo.getErrMessage());
				picmo = null;//释放资源
				//TODO 根据错误类型判断具体要做什么
				execute(cmd_none);
				break;
			case cmd_exit:
				changeState(state_none);
				stopSelf();
				break;
			default:
				//do nothing
				break;
			}
			break;
		case state_login_success:
			switch(cmd){
			case cmd_idle:
				changeState(state_idle);
				startQueue();//如果没有启动的话，需要启动了。
				break;
			default:
				break;
			}
			break;
		case state_login_fail:
			switch(cmd){
			case cmd_none:
				changeState(state_none);
				break;
			default:
				break;
			}
			break;
		//
		case state_idle:
			switch(cmd){
			case cmd_upload:
				changeState(state_uploading);
				//upload
				(new Thread(tskUpload)).start();
				break;
			case cmd_exit:
				if(imgData.isEmpty()){
					changeState(state_exit);
					stopSelf();
				}else{
					waitExit = true;//在queue里结束
				}
				break;
			default:
				//do nothing
				break;
			}
			break;
		//
		case state_uploading:
			switch(cmd){
			case res_upload_success:
				changeState(state_upload_success);
				//do something
				resUpload(true,0,"");
				execute(cmd_idle);
				break;
			case res_upload_fail:
				changeState(state_upload_fail);
				resUpload(false,picmo.getErrCode(),picmo.getErrMessage());
				//TODO 把没有上传的数据保存SD，然后继续上传
				//TODO 根据失败原因，判断时候直接结束
				/*
				if(imgData.isEmpty()){
					threadQue.stop();
					stopSelf();
				}else{
					waitExit = true;//在que里结束
				}
				*/
				execute(cmd_idle);
				break;
			case cmd_exit:
				waitExit = true;
				break;
			default:
				//do nothing
				break;
			}
			break;
		case state_upload_success:
			switch(cmd){
			case cmd_idle:
				changeState(state_idle);
				if(waitExit){
					boolean isEmpty = imgData.isEmpty();
					if(isEmpty ){
						waitExit =false;
						execute(cmd_exit);
					}
				}
				break;
			default:
				break;
			}
			break;
		case state_upload_fail:
			switch(cmd){
			case cmd_idle:
				changeState(state_idle);
				boolean isEmpty = imgData.isEmpty();
				if(isEmpty && waitExit){
					waitExit =false;
					execute(cmd_exit);
				}
				break;
			default:
				break;
			}
			break;
		//
		case state_exit:
			switch(cmd){
			case cmd_start:
				if(isReadyPicmo()){
					changeState(state_idle);//如果已经登录的话，等待上传
				}else{
					changeState(state_none);
				}
				break;
			case cmd_exit:
				stopSelf();
				break;
			default:
				break;
			}
			break;
		default:
			//do nothing
			break;
		}
	}
	
	//task
	//login
	//TODO 还没有登录成功的时候，反复Login
	//TODO 再现方法，反复进入/推出相机画面
	private String evernoteUsername;
	private String evernotePassword;
    private Runnable tskLogin = new Runnable() {          
        @Override  
        public void run() {  
        		
    		//loginReady = false;
    		logging = true;
        	picmo = new SimpleEvernote(evernoteUsername,evernotePassword);//need 20sec
        	if(!isReadyPicmo()){
        		//loginReady = false;
        		execute(res_login_fail);
        	}else{
        		//loginReady = true;
        		execute(res_login_success);
        	}
    		logging = false;
        }  
    };
	private static boolean logging ;
	private void loginPicmo(){
    	if(!logging ){
    		if(null == picmo){
	    		(new Thread(tskLogin)).start();
    		}else{
    			//do nothing
    		}
    	}
		return;
	}
	private boolean isReadyPicmo(){
		if(picmo == null){
			return false;
		}else{
			return picmo.isReady();
		}
	}
    
    //uploader
    private final Runnable tskUpload = new Runnable(){
		@Override
		public void run() {
			if(!isReadyPicmo()){
				Log.e(TAG,"@not logged.can not upload.");
			}
			//upload.need 40sec(1024x768)
			Log.d(TAG,"@uploading...");
			try {
				byte[] img;
				img = imgData.take();
				if(!picmo.picmo(img)){
					img = null;//free memory
//					Log.d(TAG,"@upload fail.");
					execute(res_upload_fail);
				}else{
					img = null;//free memory
//					Log.d(TAG,"@upload seccess.");
					execute(res_upload_success);
				}
				//threadQueue.notify();//尽快发送
/*
				//?防止间隔太短发生无法预计的错误？TODO
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				*/
			} catch (InterruptedException e) {
				Log.e(TAG,"@InterruptedException happned:"+e.getMessage());
				e.printStackTrace();
			}
		}
    };
	//Thread threadUpload = new Thread(tskUpload);

    //looper
    private final Runnable tskQueue = new Runnable(){
		@Override
		public void run() {
    		boolean isEmpty;
			for(;;){//loop
				//wait
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				//check & upload
				isEmpty = imgData.isEmpty();
				if(isEmpty){
					if(waitExit){
						break;//exit
					}
				}else{
					//upload
					switch (state){
					case state_idle:
						if(isReadyPicmo()){
							execute(cmd_upload);
						}else{
							//do nothing
						}
						break;
					default:
						break;
					}
				}
			}//for
		}
    };
    Thread threadQueue;
    //Queue线程如果没有初始化的话，初始化并启动
    //Queue线程如果结束的话，重新启动
    private void startQueue(){
		//各种线程状态的调整
		if(threadQueue == null){
			//如果线程被释放，则启动
			//Log.d(TAG,"@startQueue threadQueue is null.");
			threadQueue = new Thread(tskQueue);
			threadQueue.start();
		}else{
			//如果线程被终止，则释放原线程以后重新启动新线程
			if(threadQueue.isAlive()){
				//do nothing
			}else{
				Log.d(TAG,"@startQueue threadQueue is terminated.");
				threadQueue = null;
				threadQueue = new Thread(tskQueue);
				threadQueue.start();
			}
		}
    }

    //Queue
    private final BlockingQueue<byte[]> imgData = new LinkedBlockingQueue<byte[]>();
    //state
    private int state;
	private final void changeState(int state){
		//Log.d(TAG,"@ state "+this.state+"->"+state);
		this.state=state;
	}
	private final int state_none = 00;//初期值，需要login
	private final int state_login = 10;//login中
	private final int state_login_fail = 11;//login 但是没有成功，需要重新Login。返回主程序失败信息
	private final int state_login_success = 12;//
	private final int state_idle = 20;//login成功，可以picmo
	private final int state_uploading = 30 ;//上传中，如果有新的上传请求的话，需要排队
	private final int state_upload_fail = 31;//上次的上传失败，需要重新上传
	private final int state_upload_success = 32;//上传成功，如果没有队列的话，idle,如果有队列的话，继续下一个上传
	private final int state_exit = 100;//exit
	//command & response
	private final int cmd_none = 0;
	private final int cmd_login = 10;//
	private final int res_login_fail = 11;//
	private final int res_login_success = 12;//
	private final int cmd_idle = 20;//
	private final int cmd_upload = 30;
	private final int res_upload_fail = 31;
	private final int res_upload_success = 32;
	private final int cmd_exit = 100;
	private final int cmd_start = 101;//onStart

    //远程调用接口
	// 用aidl定义接口，并在被调用Class内部实现远程调用接口的stub类
	// service通过serviceConnect类把Stub类返回到远程调用端
	private IPicmoService.Stub rmiPicmoService = new IPicmoService.Stub() {
		@Override
		public void loginEvernote(String username, String password)
				throws RemoteException {
			if(!isReadyPicmo()){
				evernoteUsername = username;
				evernotePassword = password;
				execute(cmd_login);
			}else{
				resLogin(true,0,"");
			}
		}
		@Override
		public void picmo(byte[] img) throws RemoteException {
			try {
				if(img == null){
					Log.e(TAG,"@picmo memory is null.");//可能是照相机的内存不足了
				}else{
					imgData.put(img);//add image data to Que
				}
			} catch (InterruptedException e) {
				Log.e(TAG,"@InterruptedException happned:"+e.getMessage());
				e.printStackTrace();
			}
		}
		@Override
		public void exit() throws RemoteException {
			rmiPicmo = null;//
			execute(cmd_exit);
		}

		@Override
		public void registerCallback(IPicmo rmipicmo) throws RemoteException {
			if( rmiPicmo != null){
				rmiPicmo = null;//释放内存
			}
			rmiPicmo=rmipicmo;
			if(rmipicmo == null){
				Log.e(TAG,"@registerCallback rmiPicmo is null.");
			}
		}
	};
	//remote interface
	private IPicmo rmiPicmo;//remote interface for Picmo object
    private void resLogin(boolean result,int errcode,String errmessage){
    	if(rmiPicmo!=null){
    		try {
				rmiPicmo.resLogin(result, errcode, errmessage);
			} catch (RemoteException e) {
				Log.e(TAG,"@RemoteException happned:"+e.getMessage());
				e.printStackTrace();
			}
    	}else{
    		//do nothing
    	}
    	return;
    }
    private void resUpload(boolean result,int errcode,String errmessage){
    	if(rmiPicmo!=null){
    		try {
				rmiPicmo.resUpload(result, errcode, errmessage);
			} catch (RemoteException e) {
				Log.e(TAG,"@RemoteException happned:"+e.getMessage());
				e.printStackTrace();
			}
    	}else{
    		//do nothing
    	}
    	return;
    }
	
	private final String TAG = "**PicmoService**";
}
